package com.zeroCopy;

import org.apache.commons.io.FileUtils;

import java.io.*;
import java.net.Socket;
import java.nio.channels.FileChannel;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;


public class ZeroCopyTest {
    public static void main(String[] args) throws Exception {
        long l = System.currentTimeMillis();
        File file1 = new File("F:\\1\\2022年《Java面试题手册》.pdf");
        File file2 = new File("F:\\1\\2022年《Java面试题手册》2.pdf");
        //  copyFileUsingStream(file1,file2);  //花费====95
        // copyFileUsingApacheCommonsIO(file1,file2); //花费====16
        // copyFileUsingJava7Files(file1,file2); //花费====0
       // bufferedStreamCopyFile(file1,file2);   //花费====16
        // readerWriterCopyFile(file1,file2);  //花费====1573
       //  bufferedReaderWriterCopyFile(file1,file2);  //花费====551
         copyFileUsingFileChannels(file1,file2);  //花费====15
        long l1 = System.currentTimeMillis();
        System.out.println("花费====" + (l1 - l));

    }

    /**
     * 从源创建InputStream并使用OutputStream将其写入目标文件进行 java 复制文件操作
     *
     * @param source
     * @param dest
     * @throws IOException
     */
    private static void copyFileUsingStream(File source, File dest) throws IOException {

        InputStream is = null;
        OutputStream os = null;
        try {
            is = new FileInputStream(source);
            os = new FileOutputStream(dest);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = is.read(buffer)) > 0) {
                os.write(buffer, 0, length);
            }
        } finally {
            is.close();
            os.close();
        }

    }

    /**
     *     <dependency>
     *       <groupId>commons-io</groupId>
     *       <artifactId>commons-io</artifactId>
     *       <version>2.4</version>
     *     </dependency>
     * @param source
     * @param dest
     * @throws IOException
     */
    private static void copyFileUsingApacheCommonsIO(File source, File dest) throws IOException {
        FileUtils.copyFile(source, dest);
    }

    /**
     * Java7自带
     * @param source
     * @param dest
     * @throws IOException
     */
    private static void copyFileUsingJava7Files(File source, File dest) throws IOException {
        Files.copy(source.toPath(), dest.toPath());
    }

    /**
     * 使用BufferedInputStream/BufferedOutputStream高效字节流进行复制文件
     * @param srcFile
     * @param desFile
     * @throws Exception
     */
    private static void bufferedStreamCopyFile(File srcFile, File desFile) throws Exception {
        //使用缓冲字节流进行文件复制
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(desFile));
        byte[] b = new byte[1024];
        Integer len = 0;
        //一次读取1024字节的数据
        while ((len = bis.read(b)) != -1) {
            bos.write(b, 0, len);
        }
        bis.close();
        bos.close();
    }

    private static void readerWriterCopyFile(File srcFile, File desFile) throws IOException {
        //使用字符流进行文件复制，注意：字符流只能复制只含有汉字的文件
        FileReader fr = new FileReader(srcFile);
        FileWriter fw = new FileWriter(desFile);

        Integer by = 0;
        while ((by = fr.read()) != -1) {
            fw.write(by);
        }

        fr.close();
        fw.close();
    }

    private static void bufferedReaderWriterCopyFile(File srcFile, File desFile) throws IOException {
        //使用带缓冲区的高效字符流进行文件复制
        BufferedReader br = new BufferedReader(new FileReader(srcFile));
        BufferedWriter bw = new BufferedWriter(new FileWriter(desFile));

        char[] c = new char[1024];
        Integer len = 0;
        while ((len = br.read(c)) != -1) {
            bw.write(c, 0, len);
        }

        //方式二
         /*String s = null;
 while((s = br.readLine()) != null) {
 bw.write(s);
 bw.newLine();
 }*/

        br.close();
        bw.close();
    }

    /**
     * Java NIO包括transferFrom方法,根据文档应该比文件流复制的速度快
     * @param source
     * @param dest
     * @throws IOException
     */
    private static void copyFileUsingFileChannels(File source, File dest) throws IOException {
        FileChannel inputChannel = null;
        FileChannel outputChannel = null;
        try {
            inputChannel = new FileInputStream(source).getChannel();
            outputChannel = new FileOutputStream(dest).getChannel();
            outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
        } finally {
            inputChannel.close();
            outputChannel.close();
        }
    }

    public static void walkFileTree() throws IOException {
        File dir=new File("F:\\1");
        //可以使用实现类SimpleFileVisitor，只重写部分方法
        Files.walkFileTree(dir.toPath(), new FileVisitor<Path>() {
            // preVisitDirectory()在访问目录前被调用
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                System.out.println("pre visit dir:" + dir);
                return FileVisitResult.CONTINUE;
            }
            //visitFile()会在整个遍历过程中的每次访问文件(不包含目录)都被调用 ,
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                System.out.println("visit file: " + file);
                return FileVisitResult.CONTINUE;
            }
            //visitFileFailed()调用则是在文件（不包含目录）访问失败的时候。例如，当缺少合适的权限或者其他错误
            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                System.out.println("visit file failed: " + file);
                return FileVisitResult.CONTINUE;
            }
            //postVisitDirectory()在访问目录后调用
            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                System.out.println("post visit directory: " + dir);
                return FileVisitResult.CONTINUE;
            }
        });

    }
}
